package com.nuonuo.es.service;

import com.nuonuo.es.utils.ConvertUtils;
import com.nuonuo.es.utils.DateUtils;
import com.nuonuo.es.vo.InvoiceCodeNumberIndexVO;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.ActionFuture;
import org.elasticsearch.action.DocWriteRequest;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequestBuilder;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.cluster.metadata.AliasMetaData;
import org.elasticsearch.common.collect.ImmutableOpenMap;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.engine.VersionConflictEngineException;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

import static org.elasticsearch.index.query.QueryBuilders.boolQuery;

/**
 * @author duan
 * @version 1.0
 * @date 2023/8/30 17:56
 */
@Service
public class ElinInvoiceCodeNumService {

    private static final String INVOICE_CODE_NUMBER_ALIAS = "elin_invoice_code_num_index";

    private static final String INVOICE_CODE_NUMBER_INDEX = "elin_invoice_code_num_index_";
    private static final String INVOICE_CODE_NUMBER_TYPE = "elin_invoice_code_num";

    @Resource
    private TransportClient transportClient;

    public void save(InvoiceCodeNumberIndexVO vo) {
        Date parseDate = DateUtils.parseDate(vo.getInvoiceTime(), DateUtils.DATETIME_NO_SIGN);
        String id = (StringUtils.isBlank(vo.getInvoiceCode()) ? "" : vo.getInvoiceCode()) + vo.getInvoiceNumber();

        // 根据开票时间按年建ES索引
        String indexName = INVOICE_CODE_NUMBER_INDEX + DateUtils.getYear(parseDate);
        save(indexName, INVOICE_CODE_NUMBER_TYPE, id, vo, DocWriteRequest.OpType.CREATE);
    }

    public GetResponse get(String invoiceCode, String invoiceNum) {
        String id = (StringUtils.isBlank(invoiceCode) ? "" : invoiceCode) + invoiceNum;
        GetResponse response = transportClient.prepareGet(INVOICE_CODE_NUMBER_ALIAS, INVOICE_CODE_NUMBER_TYPE, id).get();
        return response;
    }

    /**
     * 先根据别名找到别名下的索引个数，再根据ID通过get查询每个索引数据
     * @param invoiceCode
     * @param invoiceNum
     * @return
     */
    public List<Map<String, Object>> getMulti(String invoiceCode, String invoiceNum) {
        String id = (StringUtils.isBlank(invoiceCode) ? "" : invoiceCode) + invoiceNum;
        QueryBuilder queryBuilder = QueryBuilders.boolQuery().must(QueryBuilders.matchQuery("id", id));

        ImmutableOpenMap<String, List<AliasMetaData>> map = transportClient.admin().indices().prepareGetAliases(INVOICE_CODE_NUMBER_ALIAS).get().getAliases();


        List<Map<String, Object>> list = new ArrayList<>();
        if (!map.isEmpty()) {
            Set<String> allIndices = new HashSet<>();
            map.keysIt().forEachRemaining(allIndices::add);
            for (String allIndex : allIndices) {
                GetResponse response = transportClient.prepareGet(allIndex, INVOICE_CODE_NUMBER_TYPE, id).get();
                list.add(response.getSourceAsMap());
            }
        }
        return list;
    }

    public SearchResponse search(String invoiceCode, String invoiceNum) {
        String id = (StringUtils.isBlank(invoiceCode) ? "" : invoiceCode) + invoiceNum;
        QueryBuilder queryBuilder = QueryBuilders.boolQuery().must(QueryBuilders.matchQuery("id", id));
        SearchRequestBuilder searchRequestBuilder = transportClient
                .prepareSearch(INVOICE_CODE_NUMBER_ALIAS)
                .setTypes(INVOICE_CODE_NUMBER_TYPE)
                .setSearchType(SearchType.DEFAULT)
                .setQuery(queryBuilder)
                .setFrom(0)
                .setSize(10);
        SearchResponse response = searchRequestBuilder.get(TimeValue.timeValueSeconds(5L));
        return response;
    }

    public SearchResponse search(String invoiceCode) {
        QueryBuilder queryBuilder = QueryBuilders.boolQuery().must(QueryBuilders.matchQuery("invoiceCode", invoiceCode));
        SearchRequestBuilder searchRequestBuilder = transportClient
                .prepareSearch(INVOICE_CODE_NUMBER_ALIAS)
                .setTypes(INVOICE_CODE_NUMBER_TYPE)
                .setSearchType(SearchType.DEFAULT)
                .setQuery(queryBuilder)
                .setFrom(0)
                .setSize(1);
        SearchResponse response = searchRequestBuilder.get(TimeValue.timeValueSeconds(5L));
        return response;
    }


    public SearchResponse searchByBizId(String id) {
        QueryBuilder queryBuilder = QueryBuilders.boolQuery().must(QueryBuilders.matchQuery("id", id));
        SearchRequestBuilder searchRequestBuilder = transportClient
                .prepareSearch(INVOICE_CODE_NUMBER_ALIAS)
                .setTypes(INVOICE_CODE_NUMBER_TYPE)
                .setSearchType(SearchType.DEFAULT)
                .setQuery(queryBuilder)
                .setRouting(id)
                .setFrom(0)
                .setSize(1);
        SearchResponse response = searchRequestBuilder.get(TimeValue.timeValueSeconds(5L));
        return response;
    }

    public SearchResponse searchById(String id) {
        QueryBuilder queryBuilder = QueryBuilders.boolQuery().must(QueryBuilders.matchQuery("_id", id));
        SearchRequestBuilder searchRequestBuilder = transportClient
                .prepareSearch(INVOICE_CODE_NUMBER_ALIAS)
                .setTypes(INVOICE_CODE_NUMBER_TYPE)
                .setSearchType(SearchType.DEFAULT)
                .setQuery(queryBuilder)
                .setFrom(0)
                .setSize(1);
        SearchResponse response = searchRequestBuilder.get(TimeValue.timeValueSeconds(5L));
        return response;
    }

    public SearchResponse searchByIdRouting(String id) {
        QueryBuilder  queryBuilder = QueryBuilders.boolQuery().must(QueryBuilders.matchQuery("_id", id));
        SearchRequestBuilder searchRequestBuilder = transportClient
                .prepareSearch(INVOICE_CODE_NUMBER_ALIAS)
                .setTypes(INVOICE_CODE_NUMBER_TYPE)
                .setRouting(id)
                .setSearchType(SearchType.DEFAULT)
                .setQuery(queryBuilder)
                .setFrom(0)
                .setSize(1);
        SearchResponse response = searchRequestBuilder.get(TimeValue.timeValueSeconds(5L));
        return response;
    }

    public SearchResponse searchByRouting(String id) {
        QueryBuilder  queryBuilder = QueryBuilders.boolQuery();
        SearchRequestBuilder searchRequestBuilder = transportClient
                .prepareSearch(INVOICE_CODE_NUMBER_ALIAS)
                .setTypes(INVOICE_CODE_NUMBER_TYPE)
                .setRouting(id)
                .setSearchType(SearchType.DEFAULT)
                .setQuery(queryBuilder)
                .setFrom(0)
                .setSize(1);
        SearchResponse response = searchRequestBuilder.get(TimeValue.timeValueSeconds(5L));
        return response;
    }

    private  <T> void save(String indexName, String type, String id, T object, DocWriteRequest.OpType opType) {
        IndexRequestBuilder indexRequestBuilder = transportClient.prepareIndex(indexName, type)
                .setId(id)
                .setSource(ConvertUtils.object2Map(object));

        if (Objects.nonNull(opType)) {
            indexRequestBuilder.setOpType(opType);
        }

        ActionFuture<IndexResponse> actionFuture = indexRequestBuilder.execute();
        actionFuture.actionGet();
    }

    public void delete(String invoiceCode, String invoiceNum) {
        String id = (StringUtils.isBlank(invoiceCode) ? "" : invoiceCode) + invoiceNum;
        DeleteRequest deleteRequest = new DeleteRequest(INVOICE_CODE_NUMBER_ALIAS, INVOICE_CODE_NUMBER_TYPE, id);
        transportClient.delete(deleteRequest).actionGet();
    }
}
